Imports System.IO

Public Class Renamer


    Private Const DRIVE_NOT_READY_MESSAGE As String = "Drive {0} is not ready"
    Private Const UNAUTHORIZED_ACCESS_METHOD As String = "Access to list drive/folder contents denied"

    Private Const MISSING_PATTERN_MESSAGE As String = "You have not supplied an original pattern"

    Private Const INITIAL_DRIVE As String = "C:\"
    Private Const REMOVE_PATTERN As String = ""

    Private _currentPath As String = ""

    Private Function RenameFile(ByVal fileName As String) As String

        For Each entry As Pattern In RenamePatterns.Items
            If entry.Remove Then
                fileName = fileName.Replace(entry.OldPattern, REMOVE_PATTERN)
            Else
                fileName = fileName.Replace(entry.OldPattern, entry.NewPattern)
            End If
        Next

        Return fileName.Trim

    End Function

    Private Sub LoadFileList(ByVal selectedDirectory As String)

        Dim directoryData As New DirectoryInfo(selectedDirectory & "\")

        FileSelectionList.Items.Clear()

        Try
            For Each filePresent As FileInfo In directoryData.GetFiles

                FileSelectionList.Items.Add(filePresent.Name)

            Next
        Catch ex As UnauthorizedAccessException
            Throw
        End Try

    End Sub

    Private Sub EnumerateChildren(ByVal selectedDirectory As System.Windows.Forms.TreeNode)

        Dim directoryData As New DirectoryInfo(selectedDirectory.FullPath & "\")
        Dim folder As TreeNode

        Try
            For Each subDirectory As DirectoryInfo In directoryData.GetDirectories()
                folder = New TreeNode
                folder.Text = subDirectory.Name
                folder.ImageIndex = 0
                folder.SelectedImageIndex = 1
                selectedDirectory.Nodes.Add(folder)
            Next
        Catch ex As IOException
            Throw
        Catch ex As UnauthorizedAccessException
            Throw
        Catch ex As Exception
            MsgBox("Cannot list folders of " & selectedDirectory.FullPath & ":" & ex.ToString)
        End Try

    End Sub

    Private Sub LoadDriveFolders(ByVal driveLetter As String)

        Try

            DirectoryViewer.Nodes.Clear()

            Dim root As New TreeNode
            root.ImageIndex = 0
            root.SelectedImageIndex = 1
            root.Text = Drives.SelectedItem.ToString
            DirectoryViewer.Nodes.Add(root)
            DirectoryViewer.SelectedNode = root

        Catch ex As IOException
            MsgBox(String.Format(DRIVE_NOT_READY_MESSAGE, Drives.SelectedItem))
            Drives.SelectedItem = INITIAL_DRIVE
            LoadDriveFolders(INITIAL_DRIVE)
        Catch ex As UnauthorizedAccessException
            MsgBox(UNAUTHORIZED_ACCESS_METHOD)
        End Try

    End Sub

    Private Sub LoadDrives()

        Drives.DataSource = System.IO.Directory.GetLogicalDrives
        Drives.SelectedItem = INITIAL_DRIVE
        LoadDriveFolders(INITIAL_DRIVE)

    End Sub


    Private Sub Renamer_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        LoadDrives()
        AddHandler Drives.SelectedIndexChanged, AddressOf Drives_SelectedIndexChanged

    End Sub

    Private Sub DirectoryViewer_AfterSelect(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles DirectoryViewer.AfterSelect

        If Not e.Node.IsExpanded Then
            Try
                If e.Node.GetNodeCount(False) = 0 Then
                    e.Node.ImageIndex = 1
                    e.Node.SelectedImageIndex = 1
                    EnumerateChildren(e.Node)
                End If
            Catch ex As IOException
                Throw
            Catch ex As UnauthorizedAccessException
                MsgBox(UNAUTHORIZED_ACCESS_METHOD)
                Exit Sub
            Catch ex As Exception
                MsgBox("Unable to expand " & e.Node.FullPath & ":" & ex.ToString)
            End Try
            e.Node.Expand()
        End If
        LoadFileList(e.Node.FullPath)
        _currentPath = e.Node.FullPath

    End Sub

    Private Sub Drives_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)

        LoadDriveFolders(Drives.SelectedItem.ToString)

    End Sub

    Private Sub AddPattern_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AddPattern.Click

        If OldPattern.Text.Trim.Length > 0 Then
            Dim p As New Pattern(OldPattern.Text, NewPattern.Text)
            RenamePatterns.Items.Add(p)
        Else
            MsgBox(MISSING_PATTERN_MESSAGE, MsgBoxStyle.Exclamation Or MsgBoxStyle.OkOnly)
        End If

    End Sub

    Private Sub RemovePatterns_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemovePatterns.Click

        Dim entry As Pattern
        Dim entriesToRemove As New System.Collections.ObjectModel.Collection(Of Pattern)

        For Each entry In RenamePatterns.CheckedItems
            entriesToRemove.Add(entry)
        Next

        For Each entry In entriesToRemove
            RenamePatterns.Items.Remove(entry)
        Next

    End Sub

    Private Sub SelectAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SelectAllToolStripMenuItem.Click
        For index As Integer = 0 To FileSelectionList.Items.Count - 1
            FileSelectionList.SetItemChecked(index, True)
        Next
    End Sub

    Private Sub RemoveAllToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RemoveAllToolStripMenuItem.Click
        For index As Integer = 0 To FileSelectionList.Items.Count - 1
            FileSelectionList.SetItemChecked(index, False)
        Next
    End Sub

    Private Sub RenameFiles_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RenameFiles.Click

        Dim currentDirectory As New DirectoryInfo(_currentPath & "\")
        Dim fileToRename As FileInfo
        Dim files As FileInfo()
        Dim fileName As String = ""
 
        For Each file As String In FileSelectionList.CheckedItems

            files = currentDirectory.GetFiles(file)
            If files.Length = 1 Then
                fileToRename = files(0)
                fileName = RenameFile(fileToRename.Name.ToString)
                Try
                    fileToRename.MoveTo(currentDirectory.FullName & fileName)
                Catch ex As IOException
                    'ignore error
                Catch ex As Exception
                    MsgBox(ex.Message)
                End Try
            End If
        Next

        LoadFileList(DirectoryViewer.SelectedNode.FullPath)

    End Sub

#Region " Pattern Class "

    Private Class Pattern

        Private _old As String = ""
        Private _new As String = ""
        Private _remove As Boolean = False

        Private Const REMOVE_MESSAGE As String = "Remove '{0}'"
        Private Const REPLACE_MESSAGE As String = "Replace '{0}' with '{1}'"

        Friend ReadOnly Property OldPattern() As String
            Get
                Return _old
            End Get
        End Property

        Friend ReadOnly Property NewPattern() As String
            Get
                Return _new
            End Get
        End Property

        Friend ReadOnly Property Remove() As Boolean
            Get
                Return _remove
            End Get
        End Property

        Friend Sub New(ByVal oldPattern As String, ByVal newPattern As String)

            _old = oldPattern
            _new = newPattern

            If _new.Trim.Length = 0 Then
                _remove = True
            End If

        End Sub

        Public Overrides Function ToString() As String

            If _remove Then
                Return String.Format(REMOVE_MESSAGE, _old)
            Else
                Return String.Format(REPLACE_MESSAGE, _old, _new)
            End If
        End Function

    End Class

#End Region


End Class
